#!/usr/bin/env python

import re
from gradelib import *

r = Runner(save("xv6.out"))


PTE_PRINT = """page table 0x0000000087f25000
||idx: 0: pa: 0x0000000087f21000, flags: ----
||   ||idx: 0: pa: 0x0000000087f20000, flags: ----
||   ||   ||idx: 0: va: 0x0000000000000000 -> pa: 0x0000000087f22000, flags: rwxu
||   ||   ||idx: 1: va: 0x0000000000001000 -> pa: 0x0000000087f1f000, flags: rwx-
||   ||   ||idx: 2: va: 0x0000000000002000 -> pa: 0x0000000087f1e000, flags: rwxu
||idx: 255: pa: 0x0000000087f24000, flags: ----
||   ||idx: 511: pa: 0x0000000087f23000, flags: ----
||   ||   ||idx: 510: va: 0xffffffffffffe000 -> pa: 0x0000000087f76000, flags: rw--
||   ||   ||idx: 511: va: 0xfffffffffffff000 -> pa: 0x0000000080007000, flags: r-x-"""


IDX_RE = "(idx: [0-9]+)"
VAL_RE = "(0x[0-9a-f]+)"
FLAGS_RE = "([-r][-w][-x][-u])"
INDENT_RE = r"\s*\|\|\s*"
INDENT_ESC = "\\\\s*\\|\\|\\\\s*"

@test(50, "pte printout")
def test_pteprint():
    first = True
    cur_idx = 0
    first_non_leaf_pte = True
    r.run_qemu(shell_script([
        'echo hi'
    ]))
    r.match('^hi')
    p = re.compile(VAL_RE)
    d = re.compile(INDENT_RE)
    f = re.compile(FLAGS_RE)
    for l in PTE_PRINT.splitlines() :
        l = d.sub(INDENT_ESC, l)
        l = p.sub(VAL_RE, l)
        l = f.sub(FLAGS_RE, l)
        r.match(r'^{}\s*$'.format(l))
        if first:
            first = False
        else:
            matches = re.findall(r'^{}\s*$'.format(l), r.qemu.output, re.MULTILINE)
            idx = int(re.findall(IDX_RE, l)[0][5:])
            if len(matches[0]) > 2:
                first_non_leaf_pte = True
                va = matches[0][0]
                assert_equal((int(va, 16) >> 12), idx + (cur_idx << 9))
            elif len(matches[0]) == 2:
                if first_non_leaf_pte:
                    first_non_leaf_pte = False
                    cur_idx = 0
                cur_idx = (cur_idx << 9) + idx

    

@test(10, "count copyin")
def test_count():
    r.run_qemu(shell_script([
        'stats', 'stats'
    ]), timeout=150)
    matches = re.findall(r'^copyin: (\d+)', r.qemu.output, re.MULTILINE)
    assert_equal(len(matches), 2)
    assert_equal(int(matches[1]), int(matches[0]) + 28)
    matches = re.findall(r'^copyinstr: (\d+)', r.qemu.output, re.MULTILINE)
    assert_equal(len(matches), 2)
    assert_equal(int(matches[1]), int(matches[0]) + 3)


@test(30, "kernel pagetable test")
def test_kvm():
    r.run_qemu(shell_script([
        'kvmtest'
    ]), timeout=100)
    r.match('^kvmtest: OK$')


@test(0, "usertests")
def test_usertests():
    r.run_qemu(shell_script([
        'usertests'
    ]), timeout=300)

def usertest_check(testcase, nextcase, output):
    if not re.search(r'\ntest {}: [\s\S]*OK\ntest {}'.format(testcase, nextcase), output):
        raise AssertionError('Failed ' + testcase)

@test(1, "usertests: copyin", parent=test_usertests)
def test_copyin():
    usertest_check("copyin", "copyout", r.qemu.output)

@test(1, "usertests: copyinstr1", parent=test_usertests)
def test_copyin():
    usertest_check("copyinstr1", "copyinstr2", r.qemu.output)
    
@test(1, "usertests: copyinstr2",  parent=test_usertests)
def test_copyinstr2():
    usertest_check("copyinstr2", "copyinstr3", r.qemu.output)

@test(1, "usertests: copyinstr3",  parent=test_usertests)
def test_copyinstr3():
    usertest_check("copyinstr3", "truncate1", r.qemu.output)

@test(1, "usertests: sbrkmuch",  parent=test_usertests)
def test_sbrkmuch():
    usertest_check("sbrkmuch", "kernmem", r.qemu.output)

@test(5, "usertests: all tests", parent=test_usertests)
def test_usertests():
    r.match('^ALL TESTS PASSED$')


run_tests()
